package ali

import (
	"context"
	"time"
)

type RetryQueue interface {
	Add(quick bool, task *Task)
	Pop(func() bool) (*Task, error)
	Close()
}

type Task struct {
	TaskName     string
	Ddl          int
	Q            *MQueue
}

func NewTask(name string, ddl int, q *MQueue) *Task {
	return &Task{
		name,
		ddl,
		q,
	}
}

func (t *Task) prepEnQueue(ctx context.Context) {
	timer := time.NewTimer(time.Duration(t.Ddl) * time.Second)
	for  {
		select {
		case <-timer.C:
			t.Q.EnQChan <- t
		case <-ctx.Done():
			return
		default:
		}
	}

}

type MQueue struct {
	EnQChan   chan *Task
	QuickChan chan *Task
	Stopped   bool
	ctx context.Context  //如果不知道如何关闭一个协程，就不要启动它
	cancel context.CancelFunc
}
type Error struct {
	Msg  string
	Code int
}

func (err Error) Error() string {
	return err.Msg
}
func NewQueue(cap int) *MQueue {
	ctx:=context.Background()
	subCtx,cl:=context.WithCancel(ctx)
	q := &MQueue{
		QuickChan: make(chan *Task,1),
		EnQChan:   make(chan *Task, cap),
		Stopped:   false,
		ctx: subCtx,
		cancel: cl,
	}
	return q
}

func (q *MQueue) Add(quick bool, t *Task) {
	if quick {
		q.QuickChan <- t
	} else {
		go t.prepEnQueue(q.ctx) //协程启动任务，到期自动添加进
	}
}

func (q *MQueue) Pop(f func() bool) (t *Task, err error) {
	if q.Stopped {
		return nil, Error{"任务队列已关闭", 501}
	}
	res := &Task{}
	select {
	case res = <-q.QuickChan: //有quick就先pop quick
	default: //没有quick
		select {
		case res = <-q.EnQChan:
		}
	}
	if ok := f(); !ok {
		res.Ddl++
		q.Add(false, res)
		return nil, Error{"处理函数失败,将重新调度任务", 500}
	}
	return res, nil
}

func (q *MQueue) Close() {
	close(q.EnQChan)
	close(q.QuickChan)
	q.cancel()
	q.Stopped = true //仅主协程关闭，不需要同步
}
